﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using Labthink.PCSoft.UniversalHost4.Model;
using Labthink.PCSoft.UniversalHost4.Utility;
using NLog.Fluent;
using Report.Model;

namespace Report
{
    public static class ImageFactory
    {
        // ReSharper disable once AssignNullToNotNullAttribute
        private static readonly string ImagePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Images");
        private const int W = 600;
        private const int H = 400;
        private const int L = 75;
        private const int R = 75;
        private const int T = 40;
        private const int B = 50;
        private const int Gw = W - L - R;
        private const int Gh = H - T - B;
        private const int GridNum = 10;
        private const int PaperScaleX = Gw / GridNum;
        private const int PagerScaleY = Gh / GridNum;
        private const double Num = 1.1;
        private const int MaxCount = 4000;
        private const int MinStep = 4;

        private static int _top = 5;
        private static int _left;
        //private static List<int> _spvSet = new List<int>();
        //private static string _spvLan = "";

        private static Image _img;
        private static readonly List<Color> Colors;
        private static readonly Brush Brush = new SolidBrush(Color.Black);
        private static readonly Font SFont = new Font("Arial", 6.8f, FontStyle.Regular);
        private static readonly Pen Pen = new Pen(Color.Gray, 1);

        static ImageFactory()
        {
            Colors = new List<Color>
            {
                Color.Red,
                Color.Blue,
                Color.Green,
                Color.Aqua,
                Color.Brown,
                Color.Fuchsia,
                Color.LawnGreen,
                Color.SteelBlue,
                Color.Orange,
                Color.Black
            };
        }

        public static void Clear()
        {
            if (Directory.Exists(ImagePath))
            {
                Directory.Delete(ImagePath, true);
            }
            Directory.CreateDirectory(ImagePath);
        }

        #region 单腔报告
        public static string GetReportImage(Curve curve, List<FullData> dataInfo, DataTable datas, Hashtable spvData = null)
        {
            _top = 5;
            var file = Path.Combine(ImagePath, DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".jpg");
            try
            {
                using (_img = new Bitmap(W, H))
                {
                    using (var g = Graphics.FromImage(_img))
                    {
                        g.Clear(Color.White);

                        //绘制背景
                        _drawBackground(g);

                        //绘制刻度及说明
                        _drawScaleAndCoord(g, curve, dataInfo, datas, spvData);

                        //绘制曲线
                        _drawCurve(g, curve, dataInfo, datas);

                        //绘制附加数据说明
                        //_drawSpvData(g);
                    }

                    _img.Save(file, ImageFormat.Jpeg);
                }

            }
            catch (Exception ex)
            {
                Log.Error().Message(file).Write();
                Log.Error().Exception(ex).Write();
            }

            return file;
        }

        private static void _drawScaleAndCoord(Graphics g, Curve curve, List<FullData> info, DataTable datas, Hashtable spvData)
        {
            #region 查找数据
            var dp = info.Single(d => d.DataNo == curve.X.Id);
            var col = dp.ColumnName;
            var yCol = new List<string>();
            var yTexts = new List<string>();
            var xText = dp.Text;
            if (dp.Unit != "" && dp.Unit != "null")
            {
                xText = $"{xText} ({dp.Unit})";
            }
            if (curve.Y.Count > 1)
            {
                foreach (var i in curve.Y)
                {
                    dp = info.Single(d => d.DataNo == i.Id);
                    col = $"{col},{dp.ColumnName}";
                    yCol.Add(dp.ColumnName);
                    var str = dp.Text;
                    if (dp.Unit != "" && dp.Unit != "null")
                    {
                        str = $"{str} ({dp.Unit})";
                    }
                    yTexts.Add(str);
                    if (spvData != null && spvData.Count > 0 && spvData.ContainsKey(i.Id))
                    {
                        dp = info.Single(d => d.DataNo == (int)spvData[i]);
                        col = $"{col},{dp.ColumnName}";
                        //_spvLan = dp.LanguageId;
                    }
                }
                ////var t = Win32API.GetTickCount();
                //_dtData = DBHelper.GetRealtimeDatas(DbFile, col);
                ////Console.WriteLine("数据读取时间:" + (Win32API.GetTickCount() - t));
                ////Console.WriteLine("数据条数:" + _dtData.Rows.Count);
            }
            else
            {
                // var wq = info.Single(d => d.DataNo == 10034);
                dp = info.Single(d => d.DataNo == curve.Y[0].Id);
                //col = $"{col},{dp.ColumnName}";
                yCol.Add(dp.ColumnName);
                var str = dp.Text;
                if (dp.Unit != "" && dp.Unit != "null")
                {
                    str = $"{str} ({dp.Unit})";
                }
                yTexts.Add(str);
                //dp = info.Single(d => d.DataNo == 10034);
                //var sub = datas.DefaultView.ToTable(true, dp.ColumnName);
                //var where = "";
                //if (sub.Rows.Count == 1)
                //{
                //    where = string.Format(" {0}={1}", dp.ColumnName, Curve.Subs[0]);
                //}
                //else
                //{
                //    foreach (var i in Curve.Subs)
                //    {
                //        where = string.Format("{0}{1},", where, i);
                //    }
                //    where = string.Format(" {0} in ({1})", dp.ColumnName, where.Substring(0, where.Length - 1));
                //}
                //if (SpvData.Count > 0 && SpvData.ContainsKey(Curve.Y[0]))
                //{
                //    dp = _infos.Single(d => d.DataID == (int)SpvData[Curve.Y[0]]);
                //    col = string.Format("{0},{1}", col, dp.ColumnName);
                //    _spvLan = dp.DataValue.ToString();
                //}
                ////var t = Win32API.GetTickCount();
                //_dtData = DBHelper.GetRealtimeDatas(DbFile, col + "," + wq.ColumnName, where);
                ////Console.WriteLine("数据读取时间:" + (Win32API.GetTickCount() - t));
                ////Console.WriteLine("数据条数:" + _dtData.Rows.Count);
            }
            #endregion

            #region X
            var dpx = info.Single(d => d.DataNo == curve.X.Id);
            var maxx = Convert.ToDouble(datas.Compute("Max(" + dpx.ColumnName + ")", " 1=1 ").ToString() == "" ? 10 : datas.Compute("Max(" + dpx.ColumnName + ")", " 1=1 "));
            maxx *= Num;
            if (curve.X.Min == null) curve.X.Min = 0;
            if (curve.X.Max == null) curve.X.Max = Math.Pow(10, -dpx.Precision + 1);
            if (maxx > curve.X.Max) curve.X.Max = maxx;
            else
            {
                if (maxx * 2 < curve.X.Max) curve.X.Max = maxx;
            }

            if (dpx.DataType == DataType.Int)
            {
                curve.X.Max = Math.Ceiling(curve.X.Max.Value / GridNum) * GridNum;
            }



            var xc = curve.X.Max.Value / GridNum;

            var sf = g.MeasureString(xText, SFont);
            g.DrawString(xText, SFont, Brush, L + (Gw - sf.Width) / 2, H - 25);

            for (var i = 0; i <= GridNum; i++)
            {
                var x = i * xc;
                var s = dpx.DataType == DataType.EDouble ? x.ScientificNotation(dpx.Precision) : _round(x, dpx.Precision);
                g.DrawString(s, SFont, Brush, L + i * PaperScaleX - 5, H - 45);
            }

            #endregion

            #region Y
            _left = W - R;
            _top = 25;
            if (yCol.Count == 1)
            {
                var dpy = info.Single(d => d.ColumnName == yCol[0]);
                var dmax = datas.Compute("Max(" + yCol[0] + ")", " 1=1 ").ToString();
                double my;
                if (dmax == "" || dmax == "0")
                {
                    my = 10.0;
                }
                else
                {
                    my = dmax.ToDouble();
                    my *= Num;
                }
                if (curve.Y[0].Min == null) curve.Y[0].Min = 0;
                if (curve.Y[0].Max == null) curve.Y[0].Max = Math.Pow(10, -dpy.Precision + 1);
                if (my > curve.Y[0].Max) 
                {
                    curve.Y[0].Max = my;
                }

                if (dpy.DataType == DataType.Int)
                {
                    curve.Y[0].Max = Math.Ceiling(curve.Y[0].Max.Value / GridNum) * GridNum;
                }


                var dmin = datas.Compute("Min(" + yCol[0] + ")", yCol[0] + "<>-1 ").ToString();
                if (dmin == "")
                {
                    my = 0;
                }
                else
                {
                    my = dmin.ToDouble();
                    my *= Num;
                }
                if (my < curve.Y[0].Min) curve.Y[0].Min = my;
                if (curve.Y[0].Min > 0) curve.Y[0].Min = 0;
                if (curve.Y[0].Min < -1) curve.Y[0].Min = Math.Floor(curve.Y[0].Min.Value / GridNum) * GridNum;

                sf = g.MeasureString(yTexts[0], SFont);
                g.DrawString(yTexts[0], SFont, Brush, _left - sf.Width, _top);
                _left -= (2 + (int)sf.Width);
                g.FillRectangle(Brush, _left - 20, _top + 5, 20, 5);


                var yc = (curve.Y[0].Max.Value - curve.Y[0].Min.Value) / GridNum;

                for (var i = 0; i <= GridNum; i++)
                {
                    var y = i * yc + curve.Y[0].Min.Value;
                    var s = dpy.DataType == DataType.EDouble ? y.ScientificNotation(dpy.Precision) : _round(y, dpy.Precision);
                    sf = g.MeasureString(s, SFont);
                    g.DrawString(s, SFont, Brush, L - 5 - sf.Width, H - B - i * PagerScaleY);
                }
            }
            else
            {
                for (var i = 0; i < yCol.Count; i++)
                {
                    var dpy = info.Single(d => d.ColumnName == yCol[i]);
                    var dmax = datas.Compute("Max(" + yCol[i] + ")", " 1=1 ").ToString();
                    double my;
                    if (dmax == "" || dmax == "0")
                    {
                        my = 10.0;
                    }
                    else
                    {
                        my = dmax.ToDouble();
                        my *= (Num + i / 10.0);
                    }
                    if (curve.Y[i].Min == null) curve.Y[i].Min = 0;
                    if (curve.Y[i].Max == null) curve.Y[i].Max = my;
                    if (my > curve.Y[i].Max) curve.Y[i].Max = my;


                    if (dpy.DataType == DataType.Int)
                    {
                        curve.Y[i].Max = Math.Ceiling(curve.Y[i].Max.Value / GridNum) * GridNum;
                    }
                 
                    var dmin = datas.Compute("Min(" + yCol[i] + ")", yCol[i] + "<>-1 ").ToString();
                    if (dmin == "")
                    {
                        my = 0;
                    }
                    else
                    {
                        my = dmin.ToDouble();
                        my *= Num;
                    }
                    if (my < curve.Y[i].Min) curve.Y[i].Min = my;
                    if (curve.Y[i].Min > 0) curve.Y[i].Min = 0;
                    if (curve.Y[i].Min < -1) curve.Y[i].Min = Math.Floor(curve.Y[i].Min.Value / GridNum) * GridNum;


                    sf = g.MeasureString(yTexts[i], SFont);
                    if (_left - sf.Width - 30 < L)
                    {
                        _top -= 20;
                        _left = W - R;
                    }
                    var b = new SolidBrush(Colors[i % 10]);
                    g.DrawString(yTexts[i], SFont, b, _left - sf.Width, _top);
                    _left -= (2 + (int)sf.Width);

                    g.FillRectangle(b, _left - 20, _top + 5, 20, 5);
                    _left -= 28;


                    var yc = (curve.Y[i].Max - curve.Y[i].Min) / GridNum;
                    var step = 1;
                    Font littlef;
                    if (yCol.Count > 2)
                    {
                        step = 2;
                        littlef = new Font("Arial", 6.8f, FontStyle.Regular);
                    }
                    else
                    {
                        littlef = SFont;
                    }
                    for (var j = 0; j <= GridNum; j += step)
                    {

                        var y = j * yc + curve.Y[i].Min.Value;
                        var s = dpy.DataType == DataType.EDouble ? y.Value.ScientificNotation(dpy.Precision) : _round(y.Value, dpy.Precision);
                        sf = g.MeasureString(s, SFont);
                        g.DrawString(s, littlef, b, L - 5 - sf.Width, (H - B - j * PagerScaleY - PagerScaleY / 2) + i * 12);
                    }
                }
            }
            #endregion

            #region 并列试验

            if (curve.Y.Count == 1)
            {
                dp = info.SingleOrDefault(d => d.DataNo == 10034);
                if (dp == null) return;
                var sub = datas.DefaultView.ToTable(true, dp.ColumnName);
                if (sub != null && sub.Rows.Count > 1)
                {
                    const int step = 15;
                    _top = T;
                    for (var i = 0; i < sub.Rows.Count; i++)
                    {
                        var b = new SolidBrush(Colors[i % 10]);
                        //试样
                        g.DrawString($"{info.Single(d => d.ColumnName == yCol[0]).Text} {sub.Rows[i][dp.ColumnName]}", SFont, b, L + Gw + 5, _top + i * step);
                    }
                }
            }


            #endregion
        }

        private static void _drawCurve(Graphics g, Curve curve, List<FullData> info, DataTable datas)
        {
            if (curve.Y.Count == 1)
            {
                var dp = info.Single(d => d.DataNo == 10034);
                var sub = datas.DefaultView.ToTable(true, dp.ColumnName);
                if (sub.Rows.Count <= 1)
                {
                    //单Y轴
                    //无并列试验
                    var pts = _getPoints1(g, curve, info, datas);
                    if (pts.Count() > 1)
                    {
                        g.DrawLines(new Pen(Color.Black, 1), pts);
                    }
                    else
                    {
                        g.FillRectangle(Brush, pts[0].X - 2, pts[0].Y - 2, 4, 4);
                    }
                }
                else
                {
                    //并列试验
                    _drawAll1(g, curve, info, datas);
                }
            }
            else
            {
                //多Y轴
                _drawAll2(g, curve, info, datas);
            }
        }

        private static Point[] _getPoints1(Graphics g, Curve curve, List<FullData> info, DataTable datas)
        {
            var pts = new List<Point>();

            var dpx = info.Single(d => d.DataNo == curve.X.Id);
            var dpy = info.Single(d => d.DataNo == curve.Y[0].Id);
            // ReSharper disable once PossibleInvalidOperationException
            var maxx = curve.X.Max.Value;
            // ReSharper disable once PossibleInvalidOperationException
            var minx = curve.X.Min.Value;
            // ReSharper disable once PossibleInvalidOperationException
            var maxy = curve.Y[0].Max.Value;
            // ReSharper disable once PossibleInvalidOperationException
            var miny = curve.Y[0].Min.Value;

            //if (dpx.DataType == EnDataType.DtEDouble)
            //{
            //    maxx = Convert.ToDouble(USS_Adsc.kxjs(_maxX, dpx.Precision));
            //}
            //else
            //{
            //    maxx = USS_Adsc.Round(_maxX, dpx.Precision);
            //}
            //if (dpy.DataType == EnDataType.DtEDouble)
            //{
            //    maxy = Convert.ToDouble(USS_Adsc.kxjs(_maxY[0], dpy.Precision));
            //    miny = Convert.ToDouble(USS_Adsc.kxjs(_minY[0], dpy.Precision));
            //}
            //else
            //{
            //    maxy = USS_Adsc.Round(_maxY[0], dpy.Precision);
            //    miny = USS_Adsc.Round(_minY[0], dpy.Precision);
            //}

            var step = 0;
            if (datas.Rows.Count > MaxCount)
            {
                step = (int)Math.Ceiling((double)datas.Rows.Count / MaxCount);
                if (step < MinStep) step = MinStep;
            }

            var xs = new List<double>();
            var ys = new List<double>();
            //if (SpvData.Count > 0 && SpvData.ContainsKey(Curve.Y[0]))
            //{
            //    dpa = _infos.Single(d => d.DataID == (int)SpvData[Curve.Y[0]]);
            //}
            foreach (DataRow dr in datas.Rows)
            {
                var p = new Point();
                var x = dr[dpx.ColumnName].ToDouble();
                var y = dr[dpy.ColumnName].ToDouble();
                if (step > 0)
                {

                    if (xs.Count >= step)
                    {
                        #region 过滤数据
                        //var ly = ys.Max();
                        //var sy = ys.Min();
                        //var li = ys.IndexOf(ly);
                        //var si = ys.IndexOf(sy);
                        //var lx = 0.0;
                        //var sx = 0.0;
                        //if (li > si)
                        //{
                        //    lx = xs[step / 2];
                        //    sx = xs[0];
                        //}
                        //else
                        //{
                        //    sx = xs[step / 2];
                        //    lx = xs[0];
                        //}
                        x = dpx.DataType == DataType.EDouble ? x.ScientificNotation(dpx.Precision).ToDouble() : _round(x, dpx.Precision).ToDouble();
                        y = dpy.DataType == DataType.EDouble ? y.ScientificNotation(dpy.Precision).ToDouble() : _round(y, dpy.Precision).ToDouble();
                        p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                        p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                        if (curve.IsDrawPoint)
                        {
                            g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                        }

                        pts.Add(p);

                        p = new Point();
                        x = 0.0;
                        y = 0.0;

                        x = dpx.DataType == DataType.EDouble ? x.ScientificNotation(dpx.Precision).ToDouble() : _round(x, dpx.Precision).ToDouble();
                        y = dpy.DataType == DataType.EDouble ? y.ScientificNotation(dpy.Precision).ToDouble() : _round(y, dpy.Precision).ToDouble();
                        p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                        p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                        if (curve.IsDrawPoint)
                        {
                            g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                        }

                        pts.Add(p);

                        xs.Clear();
                        ys.Clear();
                        #endregion
                    }

                    //采集数据
                    xs.Add(Convert.ToDouble(dr[0]));
                    ys.Add(Convert.ToDouble(dr[1]));

                }
                else
                {
                    x = dpx.DataType == DataType.EDouble ? x.ScientificNotation(dpx.Precision).ToDouble() : _round(x, dpx.Precision).ToDouble();
                    y = dpy.DataType == DataType.EDouble ? y.ScientificNotation(dpy.Precision).ToDouble() : _round(y, dpy.Precision).ToDouble();
                    p.X = (int)(x * Gw / maxx) + L;
                    p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                    //if (dpa != null)
                    //{
                    //    _drawSpvData(g, Color.Black, p, Convert.ToInt32(dr[2]));
                    //}
                    //else
                    {
                        if (curve.IsDrawPoint)
                        {
                            g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                        }
                    }


                    pts.Add(p);
                }

            }

            if (xs.Count > 0)
            {
                #region 过滤数据
                var p = new Point();
                var ly = ys.Max();
                var sy = ys.Min();
                var li = ys.IndexOf(ly);
                var si = ys.IndexOf(sy);
                double lx;
                double sx;
                if (li > si)
                {
                    lx = xs[xs.Count - 1];
                    sx = xs[0];
                }
                else
                {
                    sx = xs[xs.Count - 1];
                    lx = xs[0];
                }
                var x = dpx.DataType == DataType.EDouble ? sx.ScientificNotation(dpx.Precision).ToDouble() : _round(sx, dpx.Precision).ToDouble();
                var y = dpy.DataType == DataType.EDouble ? sy.ScientificNotation(dpy.Precision).ToDouble() : _round(sy, dpy.Precision).ToDouble();
                p.X = (int)((x - minx) * Gw / (maxx)) + L;
                p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                if (curve.IsDrawPoint)
                {
                    g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                }

                pts.Add(p);

                p = new Point();
                //x = 0.0;
                //y = 0.0;

                x = dpx.DataType == DataType.EDouble ? lx.ScientificNotation(dpx.Precision).ToDouble() : _round(lx, dpx.Precision).ToDouble();
                y = dpy.DataType == DataType.EDouble ? ly.ScientificNotation(dpy.Precision).ToDouble() : _round(ly, dpy.Precision).ToDouble();
                p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                if (curve.IsDrawPoint)
                {
                    g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                }

                pts.Add(p);

                xs.Clear();
                ys.Clear();
                #endregion
            }

            return pts.ToArray();
        }

        private static void _drawAll2(Graphics g, Curve curve, List<FullData> info, DataTable datas)
        {

            var dpx = info.Single(d => d.DataNo == curve.X.Id);
            // ReSharper disable once PossibleInvalidOperationException
            var maxx = curve.X.Max.Value;
            // ReSharper disable once PossibleInvalidOperationException
            var minx = curve.X.Min.Value;

            var step = 0;
            if (datas.Rows.Count > MaxCount)
            {
                step = (int)Math.Ceiling((double)datas.Rows.Count / MaxCount);
                if (step < MinStep) step = MinStep;
            }

            for (var i = 0; i < curve.Y.Count; i++)
            {
                var pts = new List<Point>();
                var dpy = info.Single(d => d.DataNo == curve.Y[i].Id);
                //DataParam dpa = null;
                //if (SpvData.Count > 0 && SpvData.ContainsKey(Curve.Y[i]))
                //{
                //    dpa = _infos.Single(d => d.DataID == (int)SpvData[Curve.Y[i]]);
                //}
                var b = new SolidBrush(Colors[i % 10]);
                // ReSharper disable once PossibleInvalidOperationException
                var maxy = curve.Y[i].Max.Value;
                // ReSharper disable once PossibleInvalidOperationException
                var miny = curve.Y[i].Min.Value;



                var xs = new List<double>();
                var ys = new List<double>();

                int nSubTestId = 0;
                if(datas.Rows.Count > 0)
                {
                    nSubTestId = datas.Rows[0]["SubTestId"].ToInt();
                }

                foreach (DataRow dr in datas.Rows)
                {
                    if (nSubTestId != dr["SubTestId"].ToInt())
                    {
                        //如果subtestid发生变化，说明一个并列试验结束，此时画曲线，然后清空数据缓存，重新遍历下一个是并列试验的数据，防止多个并列试验的曲线连在一起
                        nSubTestId = dr["SubTestId"].ToInt();
                        if (xs.Count > 0)
                        {
                            #region 过滤数据
                            var p1 = new Point();
                            var ly = ys.Max();
                            var sy = ys.Min();
                            var li = ys.IndexOf(ly);
                            var si = ys.IndexOf(sy);
                            double lx;
                            double sx;
                            if (li > si)
                            {
                                lx = xs[xs.Count - 1];
                                sx = xs[0];
                            }
                            else
                            {
                                sx = xs[xs.Count - 1];
                                lx = xs[0];
                            }
                            var x1 = dpx.DataType == DataType.EDouble ? sx.ScientificNotation(dpx.Precision).ToDouble() : _round(sx, dpx.Precision).ToDouble();
                            var y1 = dpy.DataType == DataType.EDouble ? sy.ScientificNotation(dpy.Precision).ToDouble() : _round(sy, dpy.Precision).ToDouble();
                            p1.X = (int)((x1 - minx) * Gw / (maxx - minx)) + L;
                            p1.Y = Gh + T - (int)((y1 - miny) * Gh / (maxy - miny));

                            if (curve.IsDrawPoint)
                            {
                                g.FillRectangle(Brush, p1.X - 2, p1.Y - 2, 4, 4);
                            }

                            pts.Add(p1);

                            p1 = new Point();
                            //x1 = 0.0;
                            //y1 = 0.0;

                            x1 = dpx.DataType == DataType.EDouble ? lx.ScientificNotation(dpx.Precision).ToDouble() : _round(lx, dpx.Precision).ToDouble();
                            y1 = dpy.DataType == DataType.EDouble ? ly.ScientificNotation(dpy.Precision).ToDouble() : _round(ly, dpy.Precision).ToDouble();
                            p1.X = (int)((x1 - minx) * Gw / (maxx - minx)) + L;
                            p1.Y = Gh + T - (int)((y1 - miny) * Gh / (maxy - miny));

                            if (curve.IsDrawPoint)
                            {
                                g.FillRectangle(Brush, p1.X - 2, p1.Y - 2, 4, 4);
                            }

                            pts.Add(p1);


                            #endregion
                        }

                        if (pts.Count > 1)
                        {
                            g.DrawLines(new Pen(Colors[i % 10], 1), pts.ToArray());
                        }
                        else
                        {
                            g.FillRectangle(new SolidBrush(Colors[i % 10]), pts[0].X - 2, pts[0].Y - 2, 4, 4);
                        }

                        xs.Clear();
                        ys.Clear();
                        pts = new List<Point>();
                    }

                    var p = new Point();
                    var x = dr[dpx.ColumnName].ToDouble();
                    var y = dr[dpy.ColumnName].ToDouble();
                    if (step > 0)
                    {
                        if (xs.Count >= step)
                        {
                            #region 过滤数据
                            var ly = ys.Max();
                            var sy = ys.Min();
                            var li = ys.IndexOf(ly);
                            var si = ys.IndexOf(sy);
                            double lx;
                            double sx;
                            if (li > si)
                            {
                                lx = xs[step / 2];
                                sx = xs[0];
                            }
                            else
                            {
                                sx = xs[step / 2];
                                lx = xs[0];
                            }
                            x = dpx.DataType == DataType.EDouble ? sx.ScientificNotation(dpx.Precision).ToDouble() : _round(sx, dpx.Precision).ToDouble();
                            y = dpy.DataType == DataType.EDouble ? sy.ScientificNotation(dpy.Precision).ToDouble() : _round(sy, dpy.Precision).ToDouble();
                            p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                            p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                            if (curve.IsDrawPoint)
                            {
                                g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                            }

                            pts.Add(p);

                            p = new Point();
                            //x = 0.0;
                            //y = 0.0;

                            x = dpx.DataType == DataType.EDouble ? lx.ScientificNotation(dpx.Precision).ToDouble() : _round(lx, dpx.Precision).ToDouble();
                            y = dpy.DataType == DataType.EDouble ? ly.ScientificNotation(dpy.Precision).ToDouble() : _round(ly, dpy.Precision).ToDouble();
                            p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                            p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                            if (curve.IsDrawPoint)
                            {
                                g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                            }

                            pts.Add(p);

                            xs.Clear();
                            ys.Clear();
                            #endregion
                        }

                        //采集数据
                        xs.Add(Convert.ToDouble(dr[0]));
                        ys.Add(Convert.ToDouble(dr[dpy.ColumnName]));
                    }
                    else
                    {
                        x = dpx.DataType == DataType.EDouble ? x.ScientificNotation(dpx.Precision).ToDouble() : _round(x, dpx.Precision).ToDouble();
                        y = dpy.DataType == DataType.EDouble ? y.ScientificNotation(dpy.Precision).ToDouble() : _round(y, dpy.Precision).ToDouble();
                        p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                        p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                        //if (dpa != null)
                        //{
                        //    _drawSpvData(g, _colors[i], p, Convert.ToInt32(dr[dpa.ColumnName]));
                        //}
                        //else
                        {
                            if (curve.IsDrawPoint)
                            {
                                var x0 = p.X - 2;
                                var y0 = p.Y - 2;
                                if (x0 < 0) x0 = 0;
                                if (y0 < 0) y0 = 0;
                                g.FillRectangle(b, x0, y0, 4, 4);
                            }
                        }


                        pts.Add(p);
                    }             
                }

                if (xs.Count > 0)
                {
                    #region 过滤数据
                    var p = new Point();
                    var ly = ys.Max();
                    var sy = ys.Min();
                    var li = ys.IndexOf(ly);
                    var si = ys.IndexOf(sy);
                    double lx;
                    double sx;
                    if (li > si)
                    {
                        lx = xs[xs.Count - 1];
                        sx = xs[0];
                    }
                    else
                    {
                        sx = xs[xs.Count - 1];
                        lx = xs[0];
                    }
                    var x = dpx.DataType == DataType.EDouble ? sx.ScientificNotation(dpx.Precision).ToDouble() : _round(sx, dpx.Precision).ToDouble();
                    var y = dpy.DataType == DataType.EDouble ? sy.ScientificNotation(dpy.Precision).ToDouble() : _round(sy, dpy.Precision).ToDouble();
                    p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                    p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                    if (curve.IsDrawPoint)
                    {
                        g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                    }

                    pts.Add(p);

                    p = new Point();
                    //x = 0.0;
                    //y = 0.0;

                    x = dpx.DataType == DataType.EDouble ? lx.ScientificNotation(dpx.Precision).ToDouble() : _round(lx, dpx.Precision).ToDouble();
                    y = dpy.DataType == DataType.EDouble ? ly.ScientificNotation(dpy.Precision).ToDouble() : _round(ly, dpy.Precision).ToDouble();
                    p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                    p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                    if (curve.IsDrawPoint)
                    {
                        g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                    }

                    pts.Add(p);


                    #endregion
                }

                if (pts.Count > 1)
                {
                    g.DrawLines(new Pen(Colors[i % 10], 1), pts.ToArray());
                }
                else
                {
                    g.FillRectangle(new SolidBrush(Colors[i % 10]), pts[0].X - 2, pts[0].Y - 2, 4, 4);
                }

                xs.Clear();
                ys.Clear();
                pts.Clear();
            }


        }

        private static void _drawAll1(Graphics g, Curve curve, List<FullData> info, DataTable datas)
        {

            var dpx = info.Single(d => d.DataNo == curve.X.Id);
            // ReSharper disable once PossibleInvalidOperationException
            var maxx = curve.X.Max.Value;
            // ReSharper disable once PossibleInvalidOperationException
            var minx = curve.X.Min.Value;


            var dpy = info.Single(d => d.DataNo == curve.Y[0].Id);
            // ReSharper disable once PossibleInvalidOperationException
            var maxy = curve.Y[0].Max.Value;
            // ReSharper disable once PossibleInvalidOperationException
            var miny = curve.Y[0].Min.Value;

            var step = 0;
            if (datas.Rows.Count > MaxCount)
            {
                step = (int)Math.Ceiling((double)datas.Rows.Count / MaxCount);
                if (step < MinStep) step = MinStep;
            }

            //DataParam dpa = null;
            //if (SpvData.Count > 0 && SpvData.ContainsKey(Curve.Y[0]))
            //{
            //    dpa = _infos.Single(d => d.DataID == (int)SpvData[Curve.Y[0]]);
            //}

            var wq = info.Single(d => d.DataNo == 10034);
            var sub = datas.DefaultView.ToTable(true, wq.ColumnName);
            for (var i = 0; i < sub.Rows.Count; i++)
            {
                var pts = new List<Point>();
                var b = new SolidBrush(Colors[i%10]);

                var xs = new List<double>();
                var ys = new List<double>();

                foreach (DataRow dr in datas.Select($"{wq.ColumnName}={sub.Rows[i][wq.ColumnName]}"))
                {
                    var p = new Point();
                    double x;
                    double y;
                    if (step > 0)
                    {
                        if (xs.Count >= step)
                        {
                            #region 过滤数据
                            var ly = ys.Max();
                            var sy = ys.Min();
                            var li = ys.IndexOf(ly);
                            var si = ys.IndexOf(sy);
                            double lx;
                            double sx;
                            if (li > si)
                            {
                                lx = xs[step / 2];
                                sx = xs[0];
                            }
                            else
                            {
                                sx = xs[step / 2];
                                lx = xs[0];
                            }
                            x = dpx.DataType == DataType.EDouble ? sx.ScientificNotation(dpx.Precision).ToDouble() : _round(sx, dpx.Precision).ToDouble();
                            y = dpy.DataType == DataType.EDouble ? sy.ScientificNotation(dpy.Precision).ToDouble() : _round(sy, dpy.Precision).ToDouble();
                            p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                            p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                            if (curve.IsDrawPoint)
                            {
                                g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                            }

                            pts.Add(p);

                            p = new Point();
                            //x = 0.0;
                            //y = 0.0;

                            x = dpx.DataType == DataType.EDouble ? lx.ScientificNotation(dpx.Precision).ToDouble() : _round(lx, dpx.Precision).ToDouble();
                            y = dpy.DataType == DataType.EDouble ? ly.ScientificNotation(dpy.Precision).ToDouble() : _round(ly, dpy.Precision).ToDouble();
                            p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                            p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                            if (curve.IsDrawPoint)
                            {
                                g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                            }

                            pts.Add(p);

                            xs.Clear();
                            ys.Clear();
                            #endregion
                        }

                        //采集数据
                        xs.Add(Convert.ToDouble(dr[dpx.ColumnName]));
                        ys.Add(Convert.ToDouble(dr[dpy.ColumnName]));
                    }
                    else
                    {
                        x = dpx.DataType == DataType.EDouble ? dr[dpx.ColumnName].ScientificNotation(dpx.Precision) : dr[dpx.ColumnName].Round(dpx.Precision).ToDouble();
                        y = dpy.DataType == DataType.EDouble ? dr[dpy.ColumnName].ScientificNotation(dpy.Precision) : dr[dpy.ColumnName].Round(dpy.Precision).ToDouble();
                        p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                        p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                        //if (dpa != null)
                        //{
                        //    _drawSpvData(g, _colors[i], p, Convert.ToInt32(dr[2]));
                        //}
                        //else
                        {
                            if (curve.IsDrawPoint)
                            {
                                g.FillRectangle(b, p.X - 2, p.Y - 2, 4, 4);
                            }

                        }


                        pts.Add(p);
                    }

                }

                if (xs.Count > 0)
                {
                    #region 过滤数据
                    var p = new Point();
                    var ly = ys.Max();
                    var sy = ys.Min();
                    var li = ys.IndexOf(ly);
                    var si = ys.IndexOf(sy);
                    double lx;
                    double sx;
                    if (li > si)
                    {
                        lx = xs[xs.Count - 1];
                        sx = xs[0];
                    }
                    else
                    {
                        sx = xs[xs.Count - 1];
                        lx = xs[0];
                    }
                    var x = dpx.DataType == DataType.EDouble ? sx.ScientificNotation(dpx.Precision).ToDouble() : _round(sx, dpx.Precision).ToDouble();
                    var y = dpy.DataType == DataType.EDouble ? sy.ScientificNotation(dpy.Precision).ToDouble() : _round(sy, dpy.Precision).ToDouble();
                    p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                    p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                    if (curve.IsDrawPoint)
                    {
                        g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                    }

                    pts.Add(p);

                    p = new Point();
                    //x = 0.0;
                    //y = 0.0;

                    x = dpx.DataType == DataType.EDouble ? lx.ScientificNotation(dpx.Precision).ToDouble() : _round(lx, dpx.Precision).ToDouble();
                    y = dpy.DataType == DataType.EDouble ? ly.ScientificNotation(dpy.Precision).ToDouble() : _round(ly, dpy.Precision).ToDouble();
                    p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                    p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                    if (curve.IsDrawPoint)
                    {
                        g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                    }

                    pts.Add(p);


                    #endregion
                }

                if (pts.Count > 1)
                {
                    g.DrawLines(new Pen(Colors[i % 10], 1), pts.ToArray());
                }
                else
                {
                    g.FillRectangle(new SolidBrush(Colors[i % 10]), pts[0].X - 2, pts[0].Y - 2, 4, 4);
                }
                xs.Clear();
                ys.Clear();
            }
        }
        #endregion

        #region 多腔报告
        public static string GetMuitiavityReportImage(Curve curve, List<FullData> dataInfo, DataTable datas)
        {
            _top = 5;
            var file = Path.Combine(ImagePath, DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".jpg");
            using (_img = new Bitmap(W, H))
            {

                using (var g = Graphics.FromImage(_img))
                {
                    g.Clear(Color.White);

                    //绘制背景
                    _drawBackground(g);

                    //绘制刻度及说明
                    _drawScaleAndCoord(g, curve, dataInfo, datas);

                    ////绘制曲线
                    _drawMuitiavityCurve(g, curve, dataInfo, datas);

                    //绘制附加数据说明
                    //_drawSpvData(g);
                }
                _img.Save(file, ImageFormat.Jpeg);
            }


            return file;
        }

        private static void _drawScaleAndCoord(Graphics g, Curve curve, List<FullData> info, DataTable datas)
        {
            #region 查找数据
            var dp = info.Single(d => d.DataNo == curve.X.Id);
            var col = dp.ColumnName;
            var yCol = new List<string>();
            var yTexts = new List<string>();
            var xText = dp.Text;
            if (dp.Unit != "" && dp.Unit != "null")
            {
                xText = $"{xText}(No.)";
            }
            if (curve.Y.Count > 1)
            {
                foreach (var i in curve.Y)
                {
                    dp = info.Single(d => d.DataNo == i.Id);
                    col = $"{col},{dp.ColumnName}";
                    yCol.Add(dp.ColumnName);
                    var str = dp.Text;
                    if (dp.Unit != "" && dp.Unit != "null")
                    {
                        str = $"{str} ({dp.Unit})";
                    }
                    yTexts.Add(str);

                }
            }
            else
            {
                // var wq = info.Single(d => d.DataNo == 10034);
                dp = info.Single(d => d.DataNo == curve.Y[0].Id);
                //col = $"{col},{dp.ColumnName}";
                yCol.Add(dp.ColumnName);
                var str = dp.Text;
                if (dp.Unit != "" && dp.Unit != "null")
                {
                    str = $"{str} ({dp.Unit})";
                }
                yTexts.Add(str);
            }
            #endregion

            #region X
            var dpx = info.Single(d => d.DataNo == curve.X.Id);
            var maxx = (double)datas.Rows.Count;
            maxx *= Num;
            if (curve.X.Min == null) curve.X.Min = 0;
            if (curve.X.Max == null) curve.X.Max = Math.Pow(10, -dpx.Precision + 1);
            if (maxx > curve.X.Max) curve.X.Max = maxx;
            else
            {
                if (maxx * 2 < curve.X.Max) curve.X.Max = maxx;
            }

            if (dpx.DataType == DataType.Int)
            {
                curve.X.Max = Math.Ceiling(curve.X.Max.Value / GridNum) * GridNum;
            }



            var xc = curve.X.Max.Value / GridNum;

            var sf = g.MeasureString(xText, SFont);
            g.DrawString(xText, SFont, Brush, L + (Gw - sf.Width) / 2, H - 25);
            //g.DrawString("0", SFont, Brush, L - 5, H - 45);
            for (var i = 0; i <= GridNum; i++)
            {
                var x = i * xc.ToInt();
                if (datas.Rows.Count > x)
                {
                    var id = datas.Rows[x]["TestId"];
                    var cup = datas.Rows[x][info.Single(d => d.DataNo == curve.X.Id).ColumnName];
                    var s = $"{cup}({id})";
                    g.DrawString(s, SFont, Brush, L + i * PaperScaleX - 5, H - 45);
                }
            }

            #endregion

            #region Y
            _left = W - R;
            _top = 25;
            if (yCol.Count == 1)
            {
                var dpy = info.Single(d => d.ColumnName == yCol[0]);
                var dmax = datas.Compute("Max(" + yCol[0] + ")", " 1=1 ").ToString();
                double my;
                if (dmax == "")
                {
                    my = 10.0;
                }
                else
                {
                    my = dmax.ToDouble();
                    my *= Num;
                }
                if (curve.Y[0].Min == null) curve.Y[0].Min = 0;
                if (curve.Y[0].Max == null) curve.Y[0].Max = Math.Pow(10, -dpy.Precision + 1);
                if (my > curve.Y[0].Max)
                {
                    curve.Y[0].Max = my;
                }


                if (dpy.DataType == DataType.Int)
                {
                    curve.Y[0].Max = Math.Ceiling(curve.Y[0].Max.Value / GridNum) * GridNum;
                }
                //else
                //{
                //    if (curve.Y[0].Max > 1) curve.Y[0].Max = Math.Ceiling(curve.Y[0].Max.Value);
                //}



                var dmin = datas.Compute("Min(" + yCol[0] + ")", yCol[0] + "<>-1 ").ToString();
                if (dmin == "")
                {
                    my = 0;
                }
                else
                {
                    my = dmin.ToDouble();
                    my *= Num;
                }
                if (my < curve.Y[0].Min) curve.Y[0].Min = my;
                if (curve.Y[0].Min > 0) curve.Y[0].Min = 0;
                if (curve.Y[0].Min < -1) curve.Y[0].Min = Math.Floor(curve.Y[0].Min.Value / GridNum) * GridNum;

                sf = g.MeasureString(yTexts[0], SFont);
                g.DrawString(yTexts[0], SFont, Brush, _left - sf.Width, _top);
                _left -= (2 + (int)sf.Width);
                g.FillRectangle(Brush, _left - 20, _top + 5, 20, 5);


                var yc = (curve.Y[0].Max.Value - curve.Y[0].Min.Value) / GridNum;

                for (var i = 0; i <= GridNum; i++)
                {
                    var y = i * yc + curve.Y[0].Min.Value;
                    var s = dpy.DataType == DataType.EDouble ? y.ScientificNotation(dpy.Precision) : _round(y, dpy.Precision);
                    sf = g.MeasureString(s, SFont);
                    g.DrawString(s, SFont, Brush, L - 5 - sf.Width, H - B - i * PagerScaleY);
                }
            }
            else
            {
                for (var i = 0; i < yCol.Count; i++)
                {
                    var dpy = info.Single(d => d.ColumnName == yCol[i]);
                    var dmax = datas.Compute("Max(" + yCol[i] + ")", " 1=1 ").ToString();
                    double my;
                    if (dmax == "")
                    {
                        my = 10.0;
                    }
                    else
                    {
                        my = dmax.ToDouble();
                        my *= (Num + i / 10.0);
                    }

                    if (curve.Y[i].Min == null) curve.Y[i].Min = 0;
                    if (curve.Y[i].Max == null) curve.Y[i].Max = Math.Pow(10, -dpy.Precision + 1);
                    //if (my > curve.Y[i].Max) curve.Y[i].Max = my;
                    if (my > curve.Y[i].Max)
                    {
                        curve.Y[i].Max = my; ;
                    }

                    if (dpy.DataType == DataType.Int)
                    {
                        curve.Y[i].Max = Math.Ceiling(curve.Y[i].Max.Value / GridNum) * GridNum;
                    }
                    //else
                    //{
                    //    if (curve.Y[i].Max > 1) curve.Y[i].Max = Math.Ceiling(curve.Y[i].Max.Value);
                    //}

                    var dmin = datas.Compute("Min(" + yCol[i] + ")", yCol[i] + "<>-1 ").ToString();
                    if (dmin == "")
                    {
                        my = 0;
                    }
                    else
                    {
                        my = dmin.ToDouble();
                        my *= Num;
                    }
                    if (my < curve.Y[i].Min) curve.Y[i].Min = my;
                    if (curve.Y[i].Min > 0) curve.Y[i].Min = 0;
                    if (curve.Y[i].Min < -1) curve.Y[i].Min = Math.Floor(curve.Y[i].Min.Value / GridNum) * GridNum;


                    sf = g.MeasureString(yTexts[i], SFont);
                    if (_left - sf.Width - 30 < L)
                    {
                        _top -= 20;
                        _left = W - R;
                    }
                    var b = new SolidBrush(Colors[i % 10]);
                    g.DrawString(yTexts[i], SFont, b, _left - sf.Width, _top);
                    _left -= (2 + (int)sf.Width);

                    g.FillRectangle(b, _left - 20, _top + 5, 20, 5);
                    _left -= 28;


                    var yc = (curve.Y[i].Max - curve.Y[i].Min) / GridNum;
                    var step = 1;
                    if (yCol.Count > 2) step = 2;

                    for (var j = 0; j <= GridNum; j += step)
                    {

                        var y = j * yc + curve.Y[i].Min.Value;
                        var s = dpy.DataType == DataType.EDouble ? y.Value.ScientificNotation(dpy.Precision) : _round(y.Value, dpy.Precision);
                        sf = g.MeasureString(s, SFont);
                        g.DrawString(s, SFont, b, L - 5 - sf.Width, (H - B - j * PagerScaleY - PagerScaleY / 2) + i * 12);
                    }
                }
            }
            #endregion

        }

        private static void _drawMuitiavityCurve(Graphics g, Curve curve, List<FullData> info, DataTable datas)
        {
            if (curve.Y.Count == 1)
            {
                var pts = _getMuitiavityPoints(g, curve, info, datas);
                if (pts.Count() > 1)
                {
                    g.DrawLines(new Pen(Color.Black, 1), pts);
                }
                else
                {
                    g.FillRectangle(Brush, pts[0].X - 2, pts[0].Y - 2, 4, 4);
                }
            }
            else
            {
                //多Y轴
                _drawMuitiavityPoints(g, curve, info, datas);
            }
        }

        private static Point[] _getMuitiavityPoints(Graphics g, Curve curve, List<FullData> info, DataTable datas)
        {
            var pts = new List<Point>();

            var dpy = info.Single(d => d.DataNo == curve.Y[0].Id);
            // ReSharper disable once PossibleInvalidOperationException
            var maxx = curve.X.Max.Value;
            // ReSharper disable once PossibleInvalidOperationException
            var maxy = curve.Y[0].Max.Value;
            // ReSharper disable once PossibleInvalidOperationException
            var miny = curve.Y[0].Min.Value;

            var x = -1;
            foreach (DataRow dr in datas.Rows)
            {
                var p = new Point();
                x++;
                var y = dr[dpy.ColumnName].ToDouble();
                if ((int)y == -1) continue;
                y = dpy.DataType == DataType.EDouble ? y.ScientificNotation(dpy.Precision).ToDouble() : _round(y, dpy.Precision).ToDouble();
                p.X = (int)(x * Gw / maxx) + L;
                p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));

                if (curve.IsDrawPoint)
                {
                    g.FillRectangle(Brush, p.X - 2, p.Y - 2, 4, 4);
                }
                pts.Add(p);
            }

            return pts.ToArray();
        }

        private static void _drawMuitiavityPoints(Graphics g, Curve curve, List<FullData> info, DataTable datas)
        {
            // ReSharper disable once PossibleInvalidOperationException
            var maxx = curve.X.Max.Value;
            var minx = 0;
            for (var i = 0; i < curve.Y.Count; i++)
            {
                var pts = new List<Point>();
                var dpy = info.Single(d => d.DataNo == curve.Y[i].Id);

                var b = new SolidBrush(Colors[i % 10]);
                // ReSharper disable once PossibleInvalidOperationException
                var maxy = curve.Y[i].Max.Value;
                // ReSharper disable once PossibleInvalidOperationException
                var miny = curve.Y[i].Min.Value;

                var x = -1;
                foreach (DataRow dr in datas.Rows)
                {
                    var p = new Point();
                    x++;
                    var y = dr[dpy.ColumnName].ToDouble();
                    if ((int)y == -1) continue;
                    y = dpy.DataType == DataType.EDouble ? y.ScientificNotation(dpy.Precision).ToDouble() : _round(y, dpy.Precision).ToDouble();
                    p.X = (int)((x - minx) * Gw / (maxx - minx)) + L;
                    p.Y = Gh + T - (int)((y - miny) * Gh / (maxy - miny));
                    if (curve.IsDrawPoint)
                    {
                        g.FillRectangle(b, p.X - 2, p.Y - 2, 4, 4);
                    }
                    pts.Add(p);
                }
                if (pts.Count > 1)
                {
                    g.DrawLines(new Pen(Colors[i % 10], 1), pts.ToArray());
                }
            }
        }
        #endregion

        #region 公共
        private static void _drawBackground(Graphics g)
        {
            g.DrawRectangle(Pen, L, T, Gw, Gh);

            Pen.DashStyle = DashStyle.Dash;
            for (var i = 1; i < GridNum; i++)
            {
                g.DrawLine(Pen, L, T + i * PagerScaleY, L + Gw, T + i * PagerScaleY);
                g.DrawLine(Pen, L + i * PaperScaleX, T, L + i * PaperScaleX, T + Gh);
            }
            Pen.DashStyle = DashStyle.Solid;
        }
        private static string _round(double d, int p)
        {
            string format = "0";
            if (p > 0)
            {
                for (int j = 0; j < p; j++)
                {
                    format += "0";
                }
                format = format.Insert(1, ".");
            }
            //return Math.Round(value, digits).ToString();
            return d.ToString(format);
        }
        #endregion



    }
}
